<?php

use Monolog\Formatter\JsonFormatter;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use project\common\MonologHandlerDb;
use project\common\MonologHandlerRedis;

/**
 * Class CoreLog
 * @method static bool debug($message, array $context = array())
 * @method static bool info($message, array $context = array())
 * @method static bool notice($message, array $context = array())
 * @method static bool warning($message, array $context = array())
 * @method static bool error($message, array $context = array())
 * @method static bool critical($message, array $context = array())
 * @method static bool alert($message, array $context = array())
 * @method static bool emergency($message, array $context = array())
 * @package lib\tools\logs
 */
abstract class CoreLog
{
    const METHOD_LEVEL_MAP = [
        'debug' => Logger::DEBUG,
        'info' => Logger::INFO,
        'notice' => Logger::NOTICE,
        'warning' => Logger::WARNING,
        'error' => Logger::ERROR,
        'critical' => Logger::CRITICAL,
        'alert' => Logger::ALERT,
        'emergency' => Logger::EMERGENCY,
    ];

    //使用的是 RFC 5424 https://tools.ietf.org/html/rfc5424 里定义的8个等级：debug、info、notice、warning、error、critical、alert和emergency
    protected static array $levels = [
        'debug'     => Logger::DEBUG, //详细的debug信息
        'info'      => Logger::INFO, //关键事件
        'notice'    => Logger::NOTICE, //普通但是重要的事件
        'warning'   => Logger::WARNING, //出现非错误的异常
        'error'     => Logger::ERROR, //运行时错误，但是不需要立刻处理
        'critical'  => Logger::CRITICAL, //严重错误
        'alert'     => Logger::ALERT, //Action must be taken immediately
        'emergency' => Logger::EMERGENCY //系统不可用
    ];

    protected static int $level = Logger::DEBUG;
    protected static string $channel = 'common';

    /**
     * @param $name
     * @param $arguments
     * @return bool
     * @throws \Exception
     */
    public static function __callStatic($name, $arguments)
    {
        static::$level = self::METHOD_LEVEL_MAP[$name];
        static::$channel = $_SERVER['APP_NAME'] ?? 'common';

        if (isset($arguments[1]) && is_scalar($arguments[1])) $arguments[1] = (array) $arguments[1];

        return static::getInstance()->{$name}(... $arguments);
    }

    /**
     * @return Logger
     * @throws Exception
     */
    protected static function getInstance() : Logger
    {
        //获取存储文件的名称
        $logger = new Logger(static::$channel);
        $filename = static::filename();
        $handler = [];
        //
        $reflection = CoreReflection::getInstance(static::class);
        $attributeContinue = true;
        foreach ([$reflection->getAttributes(), $reflection->getParentClass()->getAttributes()] as $attributes) {
            foreach ($attributes as $attribute) {
                $instance = $attribute->newInstance();
                //根据不同的注解处理对应问题
                if ($attributeContinue && $instance instanceof AttributeMonologHandler) {
                    $handler = $instance->getHandler();
                    $attributeContinue = false;
                    continue;
                }
            }
        }
        if (is_scalar($handler)) $handler = [$handler];
        foreach ($handler as $h) {
            match ($h) {
                MonologHandlerDb::class => $handlerItem = new MonologHandlerDb(),
                MonologHandlerRedis::class => $handlerItem = new MonologHandlerRedis(),
                default => $handlerItem = new StreamHandler($filename, static::$level),
            };
            $handlerItem->setFormatter(new JsonFormatter());
            $logger->pushHandler($handlerItem);
        }

        return $logger;
//        if (!isset(self::$_instance[static::$level]) ) { //|| !self::$_instance instanceof self
//            self::$_instance[static::$level] = $logger;
//        }
//        return self::$_instance[static::$level];
    }

    public static function filename(): string
    {

        $backtrace = debug_backtrace(0, 3);
        $backtraceDir = ltrim(str_replace(dirname(__DIR__), '', $backtrace[2]['file']), DIRECTORY_SEPARATOR);
        $dirList = explode("/", $backtraceDir);
        array_unshift($dirList, date("Ymd"));
        $file = implode('-', $dirList);
        return LOGS_ROOT. static::$channel . DIRECTORY_SEPARATOR . $file . '.log';
    }
}